#!/usr/sbin/rsct/perl5/bin/perl 
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 1999,2002 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# "@(#)01   1.44   src/rsct/registry/cli/bin/lssrtbl.perl, srcli, rsct_rpyxh, rpyxht1f3 2/22/01 16:25:32"
######################################################################
#                                                                    #
# Module: lssrtbl                                                    #
#                                                                    #
# Purpose:                                                           #
#   lssrtbl - Returns (gets) a table as a result of a selection      #
#              applied to an existing table in the System Registry.  #
#                                                                    #
# Syntax:                                                            #
#   lssrtbl [-h][-l|i|d|D Delimiter][-s][-x][-TV] Table              #
#                      [Column==Value...] [Column...]                #
#                                                                    #
# Flags:                                                             #
#   -h  Help. Writes this command's usage statement to stdout.       #
#   -i  Input file format. Display output in a format suitable for   #
#       use as input to mksrrow.                                     #
#   -l  Long form output. Metadata descriptions included in output.  #
#   -d  Delimiter formatted output. The default delimiter is a colon.#
#       ":", use the -D flag if you wish to change the default       #
#       delimiter.                                                   #
#   -D Delimiter                                                     #
#       Delimiter formatted output using the specified delimiter.    #
#       Use this flag to specify something other than the default    #
#       colon ":", when the data to be displayed may contain colons. #
#       Use this flag to specify a one or more character delimiter.  #
#   -s  Print System (SY-qualified) columns.                         #
#   -x  Exclude header. Suppress header printing.                    #
#   -T  Trace. Writes this command's trace messages to stderr.       #
#   -V  Verbose. Writes this command's verbose messages to stderr.   #
#                                                                    #
# Operands:                                                          #
#   Table   The name of the table you wish to list (get) information #
#           from. Table may contain an absolute or relative path.    #
#   Column==Value                                                    #
#           Search criteria for the select. Column name must be in   #
#           the table's metadata definition. Zero or more pairs of   #
#           these operands can be specified.                         #
#   Column  Column to be displayed to stdout. Column name must be in #
#           the table's metadata definition. Zero or more Column     #
#           operands can be specified.                               #
#                                                                    #
# Description:                                                       #
#   The lssrtbl command returns information from a table Table in the#
#   System Registry based on user defined criteria Column==Value.    #
#   Columns displayed are defined by the list of Columns as given on #
#   the command line. If no column names are given, all user defined #
#   columns are displayed. If no criteria are given, all rows in the #
#   table are returned. If multiple Column==Value pairs are provided,#
#   they are ANDed together and applied to the table.                #
#                                                                    #
#   The result of the select is displayed by default in tabular form #
#   using headers. Hexadecimal characters are used to display binary #
#   data. Use any of the [- l|i|d|D Delimiter][-s] and [-x] flags to #
#   alter the output. NOTE: The [ -x ] and [ -l|i] flags can not be  #
#   used simultaneously.  If they are, the [ -x ] flag is ignored.   #
#   See the Examples section for output samples.                     #
#                                                                    #
#   The result table is discarded at the end of the call. (Use       #
#   selectsr for the ability to save the table.)                     #
#                                                                    #
#   Use the lssr command to list the tables in the current working   #
#   directory.                                                       #
#                                                                    #
#   This command provides a simplistic method for displaying a table #
#   compared to selectsr. The format is intentionally similar to the #
#   PSSP SSDRGetObjects command. For more complex select options,    #
#   use selectsr.                                                    #
#                                                                    #
# Exit Values:                                                       #
#   0  SR_CLI_SUCCESS        Command completed successfully.         #
#   1  SR_CLI_REGISTRY_ERROR Command terminated due to an underlying #
#                            System Registry error.                  #
#   2  SR_CLI_ERROR          Command terminated due to an underlying #
#                            error in the command script.            #
#   3  SR_CLI_BAD_OPERAND    Command terminated due to user          #
#                            specifying a bad operand.               #
#   4  SR_CLI_BAD_FLAG       Command terminated due to user          #
#                            specifying an invalid flag.             #
#   5  SR_CLI_USER_ERROR     Command terminated due to a user error. #
#                            For example specifying an undefined     #
#                            table to be listed.                     #
#                                                                    #
# Examples:                                                          #
#   lssrtbl /TokenRingAdapter/Node Node_id==3 Node_name IP_address   #
#   - returns all rows with Node_id 3, displaying columns Node_name  #
#   and IP_address (from table /TokenRingAdapter/Node.)              #
#                                                                    #
#   lssrtbl -l /temp/table2                                          #
#   - displays the entire contents of /temp/table using long format. #
#                                                                    #
#   lssrtbl -dsx /temp/table2 Names Location                         #
#   - displays all rows of table /temp/table2, giving colon separated#
#   output, no headers or RowChangeCounter, using information        #
#   from columns Names and Location only                             #
#                                                                    #
#   lssrtbl /TokenRingAdapter/Node IP_address==127.0.0.1             #
#   - displays all rows of table /TokenRingAdapter/Node with         #
#   IP address 127.0.0.1.                                            #
#                                                                    #
#--------------------------------------------------------------------#
# Inputs:                                                            #
#   from command line                                                #
#                                                                    #
# Outputs:                                                           #
#   stdout - displaying help/usage statement                         #
#   stderr - displaying verbose, trace and error messages            #
#                                                                    #
# External Ref:                                                      #
#   Commands: $LSMSG                                                 #
#   Extensions:  SR.pm                                               #
#   Perl library routines: Getopts::Std                              #
#   SR cli library:  SR_cli_utils - init_session, isRelative,        #
#    $DEFAULT_GLOBAL_MOUNT_POINT term)session printCEMsg printCIMsg  #
#    close_session, set_session_variables.                           #
#                    SR_cli_display_utils - create_display           #
#                                                                    #
# Tab Settings:                                                      #
#   4 and tabs should be expanded to spaces before saving this file. #
#   in vi:  (:set ts=4  and   :%!expand -4)                          #
#                                                                    #
# Change Activity:                                                   #
#   000900 HGJ 38317: Initial delivery.                              #
#                                                                    #
######################################################################

#--------------------------------------------------------------------#
#                                                                    #
# General Program Logic/Flow:                                        #
#                                                                    #
# A: Parse command line - determine selection criteria and columns   #
#    to be returned from table given.                                #
# B: Initialize session with registry, including setting the         #
#    current directory setting depending on whether an absolute or   #
#    relative table name was given.                                  #
# C: Attempt to open table to be selected from - report error if     #
#    unsuccessful.                                                   #
# D: Call CT::SR::select  - report on success or failure             #
# E: Display table information as requested.                         #
# F: Clean up session table and tree.                                #
#                                                                    #
#--------------------------------------------------------------------#


#--------------------------------------------------------------------#
# Included Libraries                                                 #
#--------------------------------------------------------------------#
use lib "/usr/sbin/rsct/pm";
use locale;
use Getopt::Std;

use CT::CT;
use CT::CT qw(:ct_data_type_t);
use CT_cli_utils qw(printIMsg
                    printEMsg
);

use CT::SR;
use CT::SRrc;
use SR_cli_utils qw(init_session    isRelative 
                    printCEMsg      printCIMsg      
                    $DEFAULT_GLOBAL_MOUNT_POINT
                    open_table      clean_session
                    error_exit      set_session_variables
);
use SR_cli_display_utils qw(create_display);
use SR_cli_rc qw(:return_codes);


#--------------------------------------------------------------------#
# Global Variables                                                   #
#--------------------------------------------------------------------#
# Constants for use throughout the program
$TRUE              = 1;
$FALSE             = 0;

# Initialise defaults for output options 
$Opt_File_Output   = $FALSE;      # see -i flag
$Opt_Long_Output   = $FALSE;      # see -l flag 
$Opt_Delimiter     = $FALSE;      # see -d, -D flags 
$Opt_Print_SY      = $FALSE;      # see -s flag
$Opt_Print_Key     = $TRUE;       # FALSE if columns given
$Opt_No_Header     = $FALSE;      # see -x flag
$Trace             = $FALSE;      # see -T flag
$Verbose           = $FALSE;      # see -V flag 

# Message Map variables
$PROGNAME          = "lssrtbl";           # Program Name for messages
$MSGCAT            = "srcli.cat";         # msg catalogue for this cmd
$CTDIR             = "/usr/sbin/rsct";    # Cluster directory path
$CTBINDIR          = "$CTDIR/bin";        # Cluster Bin directory path
$LSMSG             = "$CTBINDIR/ctdspmsg"; # Display message routine
$ENV{'MSGMAPPATH'} = "$CTDIR/msgmaps";    # Msg maps used by $LSMSG  

%Cleanup = ();                            # Hash of items to cleanup
                                          # {Session} $session to term

#--------------------------------------------------------------------#
# Variables                                                          #
#--------------------------------------------------------------------#
# Initialise the Perl extension (Class) variables used in the program
# - this cleans up many memory problems, apparently.
my $Table_handle       = "";
my $Result_table       = CT::SR::table_handle_t->new;
my @Column_names       = ();

# These are fed into init_session
my $Tree_handle        = "";

my $Set_work_dir       = $FALSE;
my $Table              = "";
my $Table_name         = "";
my $Columns_returned   = "";
my $Select_string      = "";
my $rc                 = 0;              # assume good return code

my $Mount_point        = $DEFAULT_GLOBAL_MOUNT_POINT;


#--------------------------------------------------------------------#
# Main Code                                                          #
#--------------------------------------------------------------------#
# Parse the command line, exit if there are errors
($rc, $Table_name, $Select_string, @Column_names) = parse_cmd_line();
($rc == 0) || error_exit($rc); 

if ($Verbose) {
    if ($Columns_returned ne "") {
        $Command_line_input = sprintf "\"  %s\n  %s\n  %s\"",
                        $Table_name, $Select_string,
                        $Columns_returned;
    }
    else {
        $Command_line_input = sprintf "\"  %s\n  %s\n  %s\"",
                        $Table_name, $Select_string;
    }
    printIMsg("IMsglssrtblCommandLineInput", $Command_line_input);
}


# Establish registry session if possible. Change current directory if 
# a relative table name given, using value set in CT_SR_HOME.
# Initialise the tree handle, blessing it into tree_handle_t class
($Set_work_dir, $Table) = set_session_variables($Table_name);
($rc, $Tree_handle) = init_session($Set_work_dir);
($rc == 0) || error_exit($rc); 

# Add the tree handle to the cleanup hash
$Cleanup{Session} = $Tree_handle;


$Verbose && 
    printIMsg("IMsglssrtblListingTable", $Table_name, $Table);


# Open table to be selected on. If there's an error, close
# gracefully by ending the registry session and exiting.
($rc, $Table_handle) = open_table($Tree_handle, $Table, 
                        $Table_name, SR_READ);
($rc == 0) || error_exit($rc); 

# Add table to cleanup hash
push @{$Cleanup{Table}}, $Table_handle;

    
# Initialise variables for the select (the XSUB requires that the
# private table returned ($pvt_table) be blessed into the 
# table_handle_t class because it is declared that in the 
# parameter list.)

$Trace && print STDERR "Calling CT::SR::select\n";
$rc = CT::SR::select($Table_handle, \@Column_names, (1+$#Column_names),
                        $Result_table, $Select_string);
$Trace && print STDERR "CT::SR::select return code: $rc\n";

$rc = error_check("sr_select", $rc, $Table_name);
($rc == 0) || error_exit($rc);


# Add table to cleanup hash
push @{$Cleanup{Table}}, $Result_table;


# Print output based on user request           

if ($Opt_Long_Output) { 
    # Long form output
    $rc = create_display($Result_table, $Table_name, "long", 
                $Opt_Delimiter, $Opt_No_Header, $Opt_Print_SY, 
                $Opt_Print_Key, \@Column_names);

}
elsif ($Opt_File_Output) { 
    # Input file format printed - one row per line
    $rc = create_display($Result_table, $Table_name, "file", 
                $Opt_Delimiter, $Opt_No_Header, $Opt_Print_SY, 
                $Opt_Print_Key, \@Column_names);

}
elsif ($Opt_Delimiter) { 
    # Delimited output
    $rc = create_display($Result_table, $Table_name, "delim", 
                $Opt_Delimiter, $Opt_No_Header, $Opt_Print_SY, 
                $Opt_Print_Key, \@Column_names);
}
else { 
    # Column output by default
    $rc = create_display($Result_table, $Table_name, "column", 
                $Opt_Delimiter, $Opt_No_Header, $Opt_Print_SY, 
                $Opt_Print_Key, \@Column_names);

}

($rc == 0) || error_exit($rc); 

# Clean session and exit with any error code
$rc = clean_session($Cleanup{Session}, $Cleanup{Tables});

# Clear cleanup hash so work isn't duplicated
%Cleanup = ();
($rc == 0) || error_exit($rc); 


# Exit with $rc - if the code reaches here, it should be =0
exit $rc;

#--------------------------------------------------------------------#
# End Main Code                                                      #
#--------------------------------------------------------------------#


#--------------------------------------------------------------------#
# parse_cmd_line:                                                    #
#   Uses getopts to collect flags and input from command line        #
#   continuing to parse any remaining data in @ARGV. Name of table   #
#   to be edited is passed back to calling program.                  #
#   This subroutine will exit if it finds an error.                  #
#                                                                    #
# Return values:                                                     #
#   $local_rc   - local return code                                  #
#   $table_name - name of table to be selected from                  #
#   $select_str - selection criteria                                 #
#   $return_str - list of columns to be returned by select           #
#                                                                    #
# Global Variables Altered:                                          #
#   $Opt_Binary        output   True (-b) request for binary output  #
#   $Opt_File_Output   output   True (-i) request file format output #
#   $Opt_Print_SY      output   True (-s) print system-qualified     #
#                               columns ie RowChangeCounter          #
#   $Opt_Long_Output   output   True (-l) request long format output #
#   $Opt_No_Header     output   True (-x) request header suppression #
#   $Opt_Delimitter    output   Delimiter String (-d | -D delimitter)#
#                               When not False, display delimitter   #
#                               separated output using this del str. #
#   $Trace             output   True (-T) turn Trace mode on.        #
#   $Verbose           output   True (-V) turn Verbose mode on.      #
#--------------------------------------------------------------------#
sub parse_cmd_line
{
my $done       = 0;  
my $local_rc   = 0;
my $table_name = "";
my $select_str = "";
my $return_str = "";
my $entry      = ""; 
my $select     = 0;
my $key        = "";
my $value      = "";
my @col_names  = ();
my %opts = ();

# Get input flags, if any - exit if incorrect flag given
if (getopts('hlidD:sxTV', \%opts) == 0) {        
    printCEMsg("EMsgSRcliInvalidFlag");
    print_usage();
    return SR_CLI_BAD_FLAG;
}

# Help option given - ignore rest of command line 
if (defined $opts{h}) {   # print usage and exit
    print_usage();
    exit(0);
}

# Set Trace global if requested
if (defined $opts{T}) { 
    $Trace = $TRUE; 
}

# Set Verbose global if requested
if (defined $opts{V}) { 
    $Verbose = $TRUE; 
}

# Suppress header printing
if (defined $opts{x}) { 
    $Opt_No_Header = $TRUE; 
}

# Print (mksrrow) input file format output
if (defined $opts{i}) { 
    $Opt_File_Output = $TRUE; 
    $Opt_No_Header = $FALSE;
}

# Print System Columns
if (defined $opts{s}) { 
    $Opt_Print_SY = $TRUE; 
}

# Long form output
if (defined $opts{l}) { 
    $Opt_Long_Output = $TRUE;
    $Opt_No_Header = $FALSE;
}

# The order of these two determines which delimiter is used
# if both are defined. 

# String delimited output
if (defined $opts{D}) { 
    $Opt_Delimiter = $opts{D}; 
}

# Colon-delimited output
if (defined $opts{d} ne "") { 
    $Opt_Delimiter = ":"; 
}


# If nothing else on command line, leave message and quit -
# must have at least a table name.
if (!@ARGV) {
    printCEMsg("EMsgSRcliNoTableName");
    print_usage();
    return SR_CLI_BAD_OPERAND;
}

# Set up variables needed to process the input data.
$table_name = shift @ARGV;

# Assumption: Have table name at this point. If nothing
# else given on command line, return the entire table
if (!@ARGV) { 
    return($local_rc, $table_name, $select_str, @col_names);
}
    
# If code gets to here, there are other entries, either for the
# select string or to define columns to return.
# Start by looking for select string entries - those with '=='.
# Concatenate these entries using 'AND'. 

# May have to change this code?
$entry = shift @ARGV; 
while ( !$done && ($entry =~ /==/) ) {
    $select = $TRUE;
    $select_str .= $entry;
    if (@ARGV) {
        $entry = shift @ARGV; 
        if ($entry =~ /==/) { $select_str.= " && "; }
    }
    else { $done = $TRUE; }
}; # end while

# If no select string entries were found, return all rows in 
# the table

# If a select string was created and there is nothing left in
# @ARGV, then return all the columns in the table.
# Also, need to set $array_size to return number of columns selected
if (($select == $TRUE) && (!@ARGV)) {  
    return($local_rc, $table_name, $select_str, @col_names);
}
else {  
    # If no select strings were found (regardless of @ARGV's contents)
    # don't lose the value in $entry - it is a column to be returned.
    # still info to process, so keep going
    my $index = 0;
    $col_names[$index] = $entry;
    $return_str = $entry;   

    # Because specific columns have been given to print, set   
    # the Print Key option to false - Unless one of the columns is the
    # key column
#    $Opt_Print_Key = $FALSE;

    $index++;

    # Put the rest of @ARGV into the column to be displayed string
    foreach (@ARGV) { 
        $col_names[$index++] = $_;
        $return_str .= "'".$_."'  ";
    }
}

return($local_rc, $table_name, $select_str, @col_names);
}    # end parse_cmd_line


#--------------------------------------------------------------------#
# error_check:                                                       #
#   Checks the return code from the SR function.  If an error is     #
#   detected appropriate error messages will be displayed and        #
#   SR CLI return code set.                                          #
#                                                                    #
# Parameters:                                                        #
#   $sr_function  - Name of the SR function that was called and      #
#                   whose error code we are checking.                #
#   $sr_rc        - SR function return code.                         #
#   $table_name   - Name of the table trying to create.              #
#                                                                    #
# Return values:                                                     #
#   None.                                                            #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub error_check
{
my ($sr_function, $sr_rc, $table_name) = @_;
my $rc = 0;

if ($sr_rc != 0) {
    if ($sr_rc == SR_NO_PERMISSION) {
        printEMsg("EMsglssrtblNoPermission", $table_name);
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_CONNECTION_LOST) {
        # If this is the case, just quit
        printCEMsg("EMsgSRcliConnectionLost");
        $rc = SR_CLI_REGISTRY_ERROR;
    }
    elsif ($sr_rc == SR_NO_TABLE) {
        printEMsg("EMsglssrtblNoTableReturned");
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_NO_COLUMN) {
        printEMsg("EMsglssrtblInvalidColumn");
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_SE_NO_COLUMN) {
        printCEMsg("EMsgSRcliSENoColumn");
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_SE_ILLEGAL_COLUMN_NAME) {
        printCEMsg("EMsgSRcliSEIllegalColumnName");
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_SE_UNMATCHING_TYPE_VARIABLE) {
        printCEMsg("EMsgSRcliSEUnmatchingTypeVar");
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_SE_INVALID_OPERATOR) {
        printCEMsg("EMsgSRcliSEInvalidOperator");
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_SE_INVALID_COMPARISON) {
        printCEMsg("EMsgSRcliSEInvalidComparison");
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_SE_ILLEGAL_SELECTION_STRING) {
        printCEMsg("EMsgSRcliSEIllegalSS" );
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_SE_EXTRA_CHARS) {
        printCEMsg("EMsgSRcliSEExtraChars");
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_SE_NO_VAR_PARAMETER) {
        printCEMsg("EMsgSRcliSENoVarParameter");
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_SE_ILLEGAL_STRING_CONSTANT) {
        printCEMsg("EMsgSRcliSEIllegalStringConst");
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_SE_NULL_STRING_CONSTANT) {
        printCEMsg("EMsgSRcliSENullStringConst");
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_SE_ILLEGAL_NUMERIC_CONSTANT) {
        printCEMsg("EMsgSRcliSEIllegalNumericConst");
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_SE_NULL_NUMERIC_CONSTANT) {
        printCEMsg("EMsgSRcliSENullNumericConst");
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc < 0) {
        # TODO: temporary check for selection string errors:
        # Waiting on SR using error message code from ct utils.
        print STDERR "selectsr: selection string error\n";
        $rc = SR_CLI_USER_ERROR;
    }
    else {     
        printEMsg("EMsglssrtblErrorListingTable", $table_name, $sr_rc);
        printCEMsg("EMsgSRcliSRCommandFailure", $sr_function, $sr_rc);
        $rc = SR_CLI_REGISTRY_ERROR;
    }
}

return $rc;
}   # end error_check


#--------------------------------------------------------------------#
# print_usage : print the usage statement (syntax) to stdout.        #
#   See this command's prologue syntax section for current usage.    #
#--------------------------------------------------------------------#
sub print_usage
{
printIMsg("IMsglssrtblUsage");
}   # end print_usage


#--------------------------------------------------------------------#
# End File                                                           #
#--------------------------------------------------------------------#
